/** @file GOTHspiEeprom.c This file contains the source code for the SPI-EEPROM API of the GOTH
 * Kick-ass Etherboard.
 * 
 * This API contains all commands to control, read from and write to the EEPROM.
 *
 * @author Geoffrey Ottoy - Tom Hamelinckx
 * @date 05/07/2011 (last modified)
 *
 * <pre>
 * MODIFICATION HISTORY:
 *
 * Who  Date     Changes
 * ---- -------- ---------------------------------------------------------
 * TH   04/07/11 Created this file.
 * TH	05/07/11 Finalized, tested and documented
 * </pre>
 * 
 */

#include "GOTHspiEeprom.h"


/** Initialize EEPROM for operation.
 * 
 * @return	nothing
 *
 */
void SPI_InitEeprom(void){
	SPI_InitSpi2();
 
	AD1PCFGLbits.PCFG8 = 1; 		//Tell analog it's a digital on /CS (eeprom)
	TRISBbits.TRISB8 = 0;  			// Set /CS as output
	LATBbits.LATB8 = 1; 			// Set /CS high (so EEPROM is NOT selected)

	AD1PCFGLbits.PCFG9 = 1; 		//Tell analog it's a digital on /HOLD (eeprom)
	TRISBbits.TRISB9 = 0; 			//Set /HOLD as output
	LATBbits.LATB9 = 1; 			//Disable HOLD (EEPROM will always respond)
 }

/** Read the EEPROM's Status Register
 * Only the lowest nibble of the byte contains valid information.
 * Bit 2,3: containts Write Protected Area information
 * Bit 1  : Flags the Write Enable Latch
 * Bit 0  : Flags Write In Progress 
 * 
 * @return	The Status Register Byte.
 *
 */
unsigned char SPI_ReadSR(void){
	unsigned char dummy;
	SPI_SelectEeprom();
	SPI_TransmitReceive(EEPROM_CMD_RDSR);
	dummy = SPI_TransmitReceive(0);
	SPI_DeselectEeprom();
	return dummy;
	
} 

/** Read what areas are protected in the EEPROM
 * 
 * @return The status of the protection
 */
EEPROM_STATUS SPI_EepromGetProtectionLevel(void){
	//Protection levels are in bit 2 and 3, so mask these.
	switch( (0x0C & SPI_ReadSR()) ){
		case 0x0C:{
			return EEPROM_PROTECT_FULL;
		}break;
		case 0x08:{
			return EEPROM_PROTECT_HALF;
		}break;
		case 0x04:{
			return EEPROM_PROTECT_QUART;
		}break;
		default:{
			return FAILURE;
		}break;
	}
}

/** Change what areas are to be protected in the EEPROM
 * 
 * The user is not allowed to unprotect the area where the MAC address is stored!
 *
 * @param	status	The status (from the EEPROM_STATUS enum) to be written
 *					This can be:
 *						- EEPROM_PROTECT_QUART: Protect upper quarter (always ON!)
 *						- EEPROM_PROTECT_HALF : Protect upper half
 *						- EEPROM_PROTECT_FULL : Protect ALL
 *
 */
void SPI_EepromChangeWriteProtection(EEPROM_STATUS status){
	SPI_SelectEeprom();
	SPI_TransmitReceive(EEPROM_CMD_WRSR);
	SPI_TransmitReceive((unsigned char)status);
	SPI_DeselectEeprom();
}

/** Checks if the EEPROM is busy or not
 * 
 * @return	The status information (EEPROM_IDLE or EEPROM_BUSY)
 *
 */
EEPROM_STATUS SPI_EepromIsBusy(void){
	unsigned char maskedInfo;
	// Busy information is in bit 0, so mask this.
	maskedInfo = 0x01 & SPI_ReadSR();
	if (maskedInfo == 0x01){
		return EEPROM_BUSY;
	} else {
		return EEPROM_IDLE;
	}
}

/** Write an array of data to the EEPROM
 *
 * It is possible to write one single page in one write cycle. This implies a maximum of 16 bytes 
 * per cycle.
 * The function will return an EEPROM_PAGE_OVERFLOW error if you try to write to much data.
 * The function will return an EEPROM_BUSY error if the device is still writing the previous data.
 *
 * @param	address	The address where to write. Everything possible from 0x00 to 0xBF.
 * @param	buffer	The data that has to be stored
 * @param	length	The length of the data array to be stored.
 *
 * @return	The status information (EEPROM_PAGE_OVERFLOW or EEPROM_BUSY or EEPROM_SUCCES)
 *
 */
EEPROM_STATUS SPI_WriteEeprom(unsigned char address, unsigned char * buffer, unsigned char length){
	unsigned char page_loc, i;
	page_loc = address & 0x0F;
	if (SPI_EepromIsBusy() == EEPROM_SUCCESS){
		//Calculate max length before reaching end of page.
		if (length > (16 - page_loc)){
			//If too much: don't proceed!
			return EEPROM_PAGE_OVERFLOW;
		} else {
			//Keep in mind: After "Write Enable", device MUST first be deselected, then written!
			SPI_SelectEeprom();
			SPI_TransmitReceive(EEPROM_CMD_WREN);
			SPI_DeselectEeprom();
			SPI_SelectEeprom();
			SPI_TransmitReceive(EEPROM_CMD_WRITE);
			SPI_TransmitReceive(address);
			for(i=0; i < length; i++){
				SPI_TransmitReceive(buffer[i]);
			}
			SPI_DeselectEeprom();
			return EEPROM_SUCCESS;
		}
	} else {
		return EEPROM_BUSY;
	}
}

/** Read an array of data to the EEPROM
 *
 * The function will return an EEPROM_BUSY error if the device is still writing.
 *
 * @param	address	The address where to read from. Everything possible from 0x00 to 0xFF.
 * @param	buffer	The databuffer to put the data in.
 * @param	length	The length of the data to be stored.
 *
 * @return	The status information (EEPROM_BUSY or EEPROM_SUCCES)
 *
 */
EEPROM_STATUS SPI_ReadEeprom(unsigned char address, unsigned char * buffer, unsigned char length){
	unsigned char i;
	if (SPI_EepromIsBusy() == EEPROM_IDLE){
		SPI_SelectEeprom();
		SPI_TransmitReceive(EEPROM_CMD_READ);
		SPI_TransmitReceive(address);
		for(i=0; i < length; i++){
			buffer[i] = SPI_TransmitReceive(0);
		}
		SPI_DeselectEeprom();
		return EEPROM_SUCCESS;
	} else {
		return EEPROM_BUSY;
	}
	
}

/** Get the MAC address stored in the EEPROM
 *
 * The function will return an EEPROM_BUSY error if the device is still writing.
 *
 * @param	MACBuffer	The databuffer to put the MAC address in
 * 
 * @return	The status information (EEPROM_BUSY or EEPROM_SUCCESS)
 */
EEPROM_STATUS SPI_getMAC(unsigned char * MACBuffer){
	return SPI_ReadEeprom(0xFA, MACBuffer, 6);
}
